package com.jin.utils;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.PdfSignatureFormField;
import com.itextpdf.forms.fields.PdfTextFormField;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.styledxmlparser.jsoup.internal.StringUtil;
import com.jin.AppSwing;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class PdfUtils {
    public static PdfFont font = null;

    public static void handleFiles(List<File> files, File fileDir){
        if (fileDir.isDirectory()){
            File[] fileList = fileDir.listFiles();
            if(fileList != null){
                for (File item : fileList) {
                    handleFiles(files,item);
                }
            }
        }else{
            if(!fileDir.getName().startsWith("~$") && isDoc(fileDir.getName())){
                files.add(fileDir);
            }
        }
    }
    public static boolean isDoc(String name){
        return name.endsWith(".doc") || name.endsWith(".docx");
    }

    public static void createForm(String inPdf,String outPdf) throws Exception{
        PdfReader pdfReader = null;
        PdfWriter pdfWriter = null;
        PdfDocument pdfDocument = null;
        FileInputStream readerStream = null;
        FileOutputStream writerStream = null;
        FileOutputStream keyTxtStream = null;
        String errKey = null;
        try {
            font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
            readerStream = new FileInputStream(inPdf);
            writerStream = new FileOutputStream(outPdf);
            pdfReader = new PdfReader(readerStream);
            pdfWriter = new PdfWriter(writerStream);
            pdfDocument = new PdfDocument(pdfReader, pdfWriter);

            PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDocument, true);

            int numberOfPages = pdfDocument.getNumberOfPages();
            Set<String> allKeys = new HashSet<>();

            Map<String,List<AnnAttr>> annAttrs = new HashMap<>();

            // 查找重名key，用#号隔开
            for (int i = 1; i <= numberOfPages; i++) {
                PdfPage page = pdfDocument.getPage(i);
                List<PdfAnnotation> annotations = page.getAnnotations();
                for (PdfAnnotation annotation : annotations) {
                    PdfString contents = annotation.getContents();
                    page.removeAnnotation(annotation);
                    if (contents == null) {
                        continue;
                    }
                    String trim = annotation.getContents().toUnicodeString().trim();
                    if(trim.length() <= 4){
                        continue;
                    }
                    String keyPre = trim.substring(0, 4);
                    if(!keyPre.equalsIgnoreCase("KEY.") && !keyPre.equalsIgnoreCase("PSN.") && !keyPre.equalsIgnoreCase("CPY.")){
                        continue;
                    }
                    String key = trim.split("&")[0];

                    List<AnnAttr> annAttr = annAttrs.get(key);
                    if(annAttr == null){
                        annAttr = new ArrayList<>();
                    }
                    annAttr.add(new AnnAttr(i,trim,annotation));
                    annAttrs.put(key,annAttr);
                }
            }

            for (String keys : annAttrs.keySet()) {
                errKey = keys;
                List<AnnAttr> annAttrList = annAttrs.get(keys);
                String keyPre = keys.substring(0, 4);

                if ("KEY.".equalsIgnoreCase(keyPre)){
                    AnnAttr annAttr0 = annAttrList.get(0);
                    String singKey = annAttr0.getSignKey();
                    allKeys.add(singKey);
                    if(annAttrList.size() > 1){
                        PdfTextFormField parent = PdfTextFormField.createText(pdfDocument);
                        parent.setFont(font);
                        parent.setFontSizeAutoScale();
                        parent.put(PdfName.FT,PdfName.Tx);
                        parent.setFieldName(singKey);
                        PdfArray childPdfArray = new PdfArray() ; // PdfIndirectReference
                        parent.put(PdfName.Kids,childPdfArray);
                        PdfIndirectReference parentIr = parent.getPdfObject().getIndirectReference();
                        form.addField(parent);

                        for (int i = 0; i < annAttrList.size(); i++) {
                            AnnAttr annAttr = annAttrList.get(i);
                            PdfArray pdfArray = annAttr.getPdfAnnotation().getRectangle();
                            float x = Float.parseFloat(pdfArray.get(0).toString()) + annAttr.getX_shifting();
                            float y = Float.parseFloat(pdfArray.get(1).toString()) + Config.KEY_DEFAULT_UP_UNIT + annAttr.getY_shifting();
                            float width = Float.parseFloat(pdfArray.get(2).toString()) + annAttr.getWidth_shifting();
                            float height = Float.parseFloat(pdfArray.get(3).toString()) + annAttr.getHeight_shifting();

                            Rectangle rectangle = new Rectangle(x, y, width - x, height - y);


                            PdfFormField emptyField = PdfFormField.createEmptyField(pdfDocument);
                            emptyField.setFont(font);
                            emptyField.setFontSizeAutoScale();
                            emptyField.setFieldName((i + 1) + "");
                            emptyField.put(PdfName.F,new PdfNumber(PdfNumber.LITERAL));
                            emptyField.put(PdfName.Parent,parentIr);
                            emptyField.put(PdfName.Rect,new PdfArray(rectangle));
                            emptyField.put(PdfName.Subtype,PdfName.Widget);
                            emptyField.put(PdfName.Type,PdfName.Annot);
                            childPdfArray.add(emptyField.getPdfObject().getIndirectReference());
                            form.addField(emptyField,pdfDocument.getPage(annAttr.getPage()));
                        }
                    }else{
                        AnnAttr annAttr = annAttrList.get(0);
                        PdfArray pdfArray = annAttr.getPdfAnnotation().getRectangle();
                        float x = Float.parseFloat(pdfArray.get(0).toString()) + annAttr.getX_shifting();
                        float y = Float.parseFloat(pdfArray.get(1).toString()) + Config.KEY_DEFAULT_UP_UNIT + annAttr.getY_shifting();
                        float width = Float.parseFloat(pdfArray.get(2).toString()) + annAttr.getWidth_shifting();
                        float height = Float.parseFloat(pdfArray.get(3).toString()) + annAttr.getHeight_shifting();

                        Rectangle rectangle = new Rectangle(x, y, width - x, height - y);

                        PdfTextFormField nameField = PdfTextFormField.createText(pdfDocument, rectangle, annAttr.getSignKey());
                        nameField.setFontSizeAutoScale();
                        nameField.setFont(font);
                        form.addField(nameField, pdfDocument.getPage(annAttr.getPage()));
                    }
                }else if("PSN.".equalsIgnoreCase(keyPre)){
                    // 个人签名域
                    if(annAttrList.size() > 1){
                        throw new RuntimeException(
                                "签名域不能重复[" + keys + "]");
                    }
                    AnnAttr annAttr = annAttrList.get(0);
                    PdfArray pdfArray = annAttr.getPdfAnnotation().getRectangle();
                    float x = Float.parseFloat(pdfArray.get(0).toString()) + annAttr.getX_shifting();
                    float y = Float.parseFloat(pdfArray.get(1).toString()) + Config.KEY_DEFAULT_UP_UNIT + annAttr.getY_shifting();
                    float width = Config.PSN_DEFAULT_WIDTH + annAttr.getWidth_shifting();
                    float height = Config.PSN_DEFAULT_HEIGHT + annAttr.getHeight_shifting();

                    Rectangle rectangle = new Rectangle(x, y, width, height);
                    PdfSignatureFormField signature = PdfSignatureFormField.createSignature(pdfDocument, rectangle);
                    signature.setFieldName(annAttr.getSignKey());
                    signature.setVisibility(PdfFormField.VISIBLE);
                    form.addField(signature, pdfDocument.getPage(annAttr.getPage()));
                }else if("CPY.".equalsIgnoreCase(keyPre)){
                    // 公司签名域
                    if(annAttrList.size() > 1){
                        throw new RuntimeException(
                                "签名域不能重复[" + keys + "]");
                    }
                    AnnAttr annAttr = annAttrList.get(0);
                    PdfArray pdfArray = annAttr.getPdfAnnotation().getRectangle();
                    float x = Float.parseFloat(pdfArray.get(0).toString()) + annAttr.getX_shifting();
                    float y = Float.parseFloat(pdfArray.get(1).toString()) + annAttr.getY_shifting();
                    float width = Config.CPY_DEFAULT_WIDTH + annAttr.getWidth_shifting();
                    float height = Config.CPY_DEFAULT_HEIGHT + annAttr.getHeight_shifting();

                    Rectangle rectangle = new Rectangle(x, y, width, height);
                    PdfSignatureFormField signature = PdfSignatureFormField.createSignature(pdfDocument, rectangle);
                    signature.setFieldName(annAttr.getSignKey());
                    signature.setVisibility(PdfFormField.VISIBLE);
                    form.addField(signature, pdfDocument.getPage(annAttr.getPage()));
                }
            }

            keyTxtStream = new FileOutputStream(outPdf.substring(0, outPdf.lastIndexOf(".")) + "-key.txt");
            String keysStr = StringUtil.join(allKeys, ";");
            keyTxtStream.write(keysStr.getBytes(StandardCharsets.UTF_8));
        }catch (Exception e){
            if(errKey != null){
                AppSwing.appendLog("error:key[" + errKey + "]");
            }
            throw e;
        }finally {
            if(pdfDocument != null){
                pdfDocument.close();
            }
            if(readerStream != null){
                try{readerStream.close();}catch (Exception ignored){}
            }
            if(keyTxtStream != null){
                try{keyTxtStream.close();}catch (Exception ignored){}
            }
        }
    }


    public static class AnnAttr{
        private final Integer page;
        private final String contents;
        private final PdfAnnotation pdfAnnotation;
        private String key;
        private String signKey;
        private float x_shifting;
        private float y_shifting;
        private float width_shifting;
        private float height_shifting;

        public AnnAttr(Integer page,String key,PdfAnnotation pdfAnnotation){
            this.page = page;
            this.contents = key;
            this.pdfAnnotation = pdfAnnotation;
            initRect();
        }

        public Integer getPage() {
            return page;
        }

        public String getContents() {
            return contents;
        }

        public PdfAnnotation getPdfAnnotation() {
            return pdfAnnotation;
        }

        private void initRect(){
            // 兼容方框里边打勾
            String custom = null;
            String key = contents;
            if (contents.contains("&")) {
                String[] split = contents.split("&");
                key = split[0];
                if(split.length > 1){
                    custom = split[1];
                }else{
                    custom = "";
                }
            }

            // 自定义位置偏移
            float x_shifting = 0;
            float y_shifting = 0;
            float width_shifting = 0;
            float height_shifting = 0;
            if (custom != null) {
                if (custom.trim().length() == 0) {
                    x_shifting = 1.7f;
                    y_shifting = 1.7f ;
                    width_shifting = -1.7f;
                    height_shifting = -4.2f;
                } else {
                    String[] customs = custom.split(" ");
                    if (customs.length != 4) {
                        throw new RuntimeException(
                                "[" + contents + "]自定义格式不符合规范，请参考文档保持[key.**&x y w h]格式,a、b、d均为数字，可以，x: 左边往右偏移，y: 底边往上偏移，w: 宽偏移，h：高偏移");
                    }
                    x_shifting = Float.parseFloat(customs[0]);
                    y_shifting = Float.parseFloat(customs[1]);
                    width_shifting = Float.parseFloat(customs[2]);
                    height_shifting = Float.parseFloat(customs[3]);
                }
            }
            this.key = key;
            this.signKey = key.substring(4);
            this.x_shifting = x_shifting;
            this.y_shifting = y_shifting;
            this.width_shifting = width_shifting;
            this.height_shifting = height_shifting;
        }

        public String getKey() {
            return key;
        }

        public String getSignKey() {
            return signKey;
        }

        public float getHeight_shifting() {
            return height_shifting;
        }

        public float getWidth_shifting() {
            return width_shifting;
        }

        public float getX_shifting() {
            return x_shifting;
        }

        public float getY_shifting() {
            return y_shifting;
        }
    }
}
